package com.xframe.xdal.core.handler.es;

import com.alibaba.fastjson.JSON;
import com.xframe.xdal.core.constant.RunOpportunity;
import com.xframe.xdal.core.handler.BeanHandlerOptions;
import com.xframe.xdal.core.handler.IAfterConstruction;
import com.xframe.xdal.core.handler.IBeanInit;
import com.xframe.xdal.core.model.IModel;
import lombok.extern.log4j.Log4j2;
import org.elasticsearch.search.SearchHits;

import java.util.Collection;
import java.util.Map;
/**
 * 功能描述: 基于ES的查询处理器，将SearchHits返回成集合对象
 *
 * @author xufeng
 * @version 1.0
 * @date 2023-03-20
 */
@Log4j2
public class EsBeanListHandler<E,T> implements ISearchHitsHandler<E> {

    /**
     * 设置的参数对象
     */
    private BeanHandlerOptions beanHandlerOptions;

    /**
     * 类型 ResultHandler
     */
    private final Class<T> elementBeanType;

    public static <E,T> EsBeanListHandler<E,T> create(Class<E> beanType, BeanHandlerOptions beanHandlerOptions){
        return new EsBeanListHandler(beanType,beanHandlerOptions);
    }

    public EsBeanListHandler(Class<T> beanType, BeanHandlerOptions beanHandlerOptions){
        this.elementBeanType = beanType;
        this.beanHandlerOptions = beanHandlerOptions;
    }


    private E newInstance() throws InstantiationException, IllegalAccessException {

        Object list = this.beanHandlerOptions.getCollectionInstance();
        return (E) list;
    }

    @Override
    public E handle(SearchHits searchHits) {
        try {
            if (searchHits == null) {
                return null;
            }
            E list = newInstance();

            searchHits.forEach(searchHit ->{
                try {

                    String json = searchHit.getSourceAsString();

                    T bean = beanHandlerOptions.toObject(json,elementBeanType);
                    if(bean instanceof IAfterConstruction){
                        afterConstruction(((IAfterConstruction)bean));
                    }
                    beanHandlerOptions.getAutoProcRuntime().autoFill(bean,beanHandlerOptions.getTableInfo(), RunOpportunity.R);
                    if(bean instanceof IBeanInit){
                        initBean(((IBeanInit)bean));
                    }
                    // 添加过滤器逻辑
                    if(this.execBeanListHandlerCallBack(bean)){
                        addTo(list,bean);
                    }

                }catch (Exception exception){
                    exception.printStackTrace();
                }

            });
            return list;
        }catch (Exception exception) {
            exception.printStackTrace();
            //log.error("exception={}",exception);
            return null;
        }

    }

    @Override
    public void handleMerge(SearchHits searchHits, E result) {
        try {
            if (searchHits == null) {
                return;
            }
            if (result == null) {
                result = newInstance();
            }
            E finalResult = result;
            searchHits.forEach(searchHit ->{
                try {
                    String json = searchHit.getSourceAsString();
                    T bean =  JSON.parseObject(json, elementBeanType);
                    if(bean instanceof IAfterConstruction){
                        afterConstruction(((IAfterConstruction)bean));
                    }
                    beanHandlerOptions.getAutoProcRuntime().autoFill(bean,beanHandlerOptions.getTableInfo(), RunOpportunity.R);
                    if(bean instanceof IBeanInit){
                        initBean(((IBeanInit)bean));
                    }
                    // 添加过滤器逻辑
                    if(this.execBeanListHandlerCallBack(bean)){
                        addTo(finalResult,bean);
                    }

                }catch (Exception exception){
                    exception.printStackTrace();
                }
            });
        }catch (Exception exception) {
            exception.printStackTrace();
            //log.error("exception={}",exception);
        }
    }

    private void addTo(E list,T bean){
        if(list instanceof Collection){
            ((Collection)list).add(bean);
        }
        if(list instanceof Map){
            if(this.beanHandlerOptions.getModelMapKey() != null){
                ((Map) list).put(this.beanHandlerOptions.getModelMapKey().getMapkey(bean), bean);
            }
            else if(bean instanceof IModel){
                ((Map) list).put(((IModel)bean).getMapkey(), bean);
            }else {
                ((Map) list).put(bean.hashCode(), bean);
            }
        }
    }


    protected void afterConstruction(IAfterConstruction bean){
        try{
            bean.build();
        }catch (Exception exception){
            exception.printStackTrace();
        }
    }


    protected void initBean(IBeanInit bean){
        try{
            bean.init();
        }catch (Exception exception){
            exception.printStackTrace();
        }
    }


    protected boolean execBeanListHandlerCallBack(T bean){
        if(beanHandlerOptions.getBeanListHandlerCallBack() == null){
            return true;
        }
        try {
            return beanHandlerOptions.getBeanListHandlerCallBack().filter(bean);
        }catch (Exception exception){
            exception.printStackTrace();
            return true;
        }

    }
}
